package com.aviatorscript.avitorscriptmust.service.impl;

import com.aviatorscript.avitorscriptmust.dto.ValidationConfigDTO;
import com.aviatorscript.avitorscriptmust.entity.FieldValidationConfig;
import com.aviatorscript.avitorscriptmust.mapper.FieldValidationConfigMapper;
import com.aviatorscript.avitorscriptmust.service.FieldValidationConfigService;
import com.aviatorscript.avitorscriptmust.cache.AviatorValidationCacheManager;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.AviatorEvaluatorInstance;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 字段校验配置Service实现类
 *
 * @author system
 */
@Slf4j
@Service
public class FieldValidationConfigServiceImpl extends ServiceImpl<FieldValidationConfigMapper, FieldValidationConfig>
        implements FieldValidationConfigService {
    
    @Autowired
    private AviatorValidationCacheManager cacheManager;
    
    /**
     * AviatorScript引擎实例（用于语法校验）
     */
    private final AviatorEvaluatorInstance aviatorEngine = AviatorEvaluator.newInstance();
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createValidationRule(ValidationConfigDTO dto) {
        log.info("创建校验规则: {}", dto.getRuleName());
        
        // 1. 校验脚本语法
        String validationMessage = validateScript(dto.getScriptContent());
        if (!"脚本语法正确".equals(validationMessage)) {
            throw new RuntimeException("脚本语法错误: " + validationMessage);
        }
        
        // 2. 检查规则名称和字段路径是否重复
        LambdaQueryWrapper<FieldValidationConfig> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FieldValidationConfig::getClassName, dto.getClassName())
                   .eq(FieldValidationConfig::getFieldPath, dto.getFieldPath())
                   .eq(FieldValidationConfig::getStatus, 1);
        
        FieldValidationConfig existingConfig = this.getOne(queryWrapper);
        if (existingConfig != null) {
            throw new RuntimeException("该类的字段路径已存在校验规则: " + dto.getFieldPath());
        }
        
        // 3. 创建新的配置
        FieldValidationConfig config = new FieldValidationConfig();
        BeanUtils.copyProperties(dto, config);
        config.setCreateTime(LocalDateTime.now());
        config.setUpdateTime(LocalDateTime.now());
        
        // 4. 保存到数据库
        boolean saved = this.save(config);
        if (!saved) {
            throw new RuntimeException("保存校验规则失败");
        }
        
        // 5. 刷新缓存
        cacheManager.refreshCache(dto.getClassName());
        
        log.info("校验规则创建成功: id={}, ruleName={}", config.getId(), config.getRuleName());
        return config.getId();
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateValidationRule(Long id, ValidationConfigDTO dto) {
        log.info("更新校验规则: id={}, ruleName={}", id, dto.getRuleName());
        
        // 1. 检查配置是否存在
        FieldValidationConfig existingConfig = this.getById(id);
        if (existingConfig == null) {
            throw new RuntimeException("校验规则不存在: " + id);
        }
        
        // 2. 校验脚本语法
        String validationMessage = validateScript(dto.getScriptContent());
        if (!"脚本语法正确".equals(validationMessage)) {
            throw new RuntimeException("脚本语法错误: " + validationMessage);
        }
        
        // 3. 检查字段路径是否与其他规则冲突
        LambdaQueryWrapper<FieldValidationConfig> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FieldValidationConfig::getClassName, dto.getClassName())
                   .eq(FieldValidationConfig::getFieldPath, dto.getFieldPath())
                   .eq(FieldValidationConfig::getStatus, 1)
                   .ne(FieldValidationConfig::getId, id);
        
        FieldValidationConfig conflictConfig = this.getOne(queryWrapper);
        if (conflictConfig != null) {
            throw new RuntimeException("该类的字段路径已存在校验规则: " + dto.getFieldPath());
        }
        
        // 4. 更新配置
        String oldClassName = existingConfig.getClassName();
        BeanUtils.copyProperties(dto, existingConfig);
        existingConfig.setId(id);
        existingConfig.setUpdateTime(LocalDateTime.now());
        
        boolean updated = this.updateById(existingConfig);
        if (!updated) {
            throw new RuntimeException("更新校验规则失败");
        }
        
        // 5. 刷新缓存（如果类名发生变化，需要刷新两个类的缓存）
        cacheManager.refreshCache(dto.getClassName());
        if (!oldClassName.equals(dto.getClassName())) {
            cacheManager.refreshCache(oldClassName);
        }
        
        log.info("校验规则更新成功: id={}, ruleName={}", id, dto.getRuleName());
        return true;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteValidationRule(Long id) {
        log.info("删除校验规则: id={}", id);
        
        // 1. 检查配置是否存在
        FieldValidationConfig existingConfig = this.getById(id);
        if (existingConfig == null) {
            throw new RuntimeException("校验规则不存在: " + id);
        }
        
        // 2. 删除配置
        boolean deleted = this.removeById(id);
        if (!deleted) {
            throw new RuntimeException("删除校验规则失败");
        }
        
        // 3. 刷新缓存
        cacheManager.refreshCache(existingConfig.getClassName());
        
        log.info("校验规则删除成功: id={}, ruleName={}", id, existingConfig.getRuleName());
        return true;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateStatus(Long id, Integer status) {
        log.info("更新校验规则状态: id={}, status={}", id, status);
        
        // 1. 检查配置是否存在
        FieldValidationConfig existingConfig = this.getById(id);
        if (existingConfig == null) {
            throw new RuntimeException("校验规则不存在: " + id);
        }
        
        // 2. 更新状态
        existingConfig.setStatus(status);
        existingConfig.setUpdateTime(LocalDateTime.now());
        
        boolean updated = this.updateById(existingConfig);
        if (!updated) {
            throw new RuntimeException("更新校验规则状态失败");
        }
        
        // 3. 刷新缓存
        cacheManager.refreshCache(existingConfig.getClassName());
        
        log.info("校验规则状态更新成功: id={}, status={}", id, status);
        return true;
    }
    
    @Override
    public List<FieldValidationConfig> getEnabledRulesByClassName(String className) {
        LambdaQueryWrapper<FieldValidationConfig> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FieldValidationConfig::getClassName, className)
                   .eq(FieldValidationConfig::getStatus, 1)
                   .orderByAsc(FieldValidationConfig::getPriority);
        
        return this.list(queryWrapper);
    }
    
    @Override
    public List<FieldValidationConfig> getAllEnabledRules() {
        LambdaQueryWrapper<FieldValidationConfig> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FieldValidationConfig::getStatus, 1)
                   .orderByAsc(FieldValidationConfig::getClassName)
                   .orderByAsc(FieldValidationConfig::getPriority);
        
        return this.list(queryWrapper);
    }
    
    @Override
    public String validateScript(String scriptContent) {
        try {
            // 创建测试环境变量
            Map<String, Object> env = new HashMap<>();
            env.put("fieldValue", "test");
            env.put("dto", new Object());
            env.put("fieldPath", "testField");
            
            // 尝试编译和执行脚本
            Object result = aviatorEngine.execute(scriptContent, env);
            
            // 检查返回结果格式是否正确
            if (result instanceof Map) {
                @SuppressWarnings("unchecked")
                Map<String, Object> resultMap = (Map<String, Object>) result;
                if (!resultMap.containsKey("valid")) {
                    return "脚本必须返回包含'valid'字段的Map对象";
                }
                return "脚本语法正确";
            } else {
                return "脚本必须返回Map类型的结果";
            }
            
        } catch (Exception e) {
            log.warn("脚本语法校验失败: {}", e.getMessage());
            return "脚本语法错误: " + e.getMessage();
        }
    }
} 